/**
 ******************************************************************************
 * @file           : bsp_adc.c
 * @brief          : ADC Driver Implementation (STM32H7xx)
 ******************************************************************************
 * @attention
 *
 * ADC驱动程序实现文件
 * 提供单通道、多通道采集等功能
 * 支持内部温度传感器和参考电压采集
 *
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "./BSP/ADC/bsp_adc.h"
#include "./BSP/ADC/bsp_adc_config.h"

/* Private includes ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define ADC_READ_TIMEOUT            1000        /*!< ADC读取超时时间(ms) */
#define ADC_CALIBRATION_TIMEOUT     1000        /*!< ADC校准超时时间(ms) */

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static ADC_HandleTypeDef sg_adc_handle;                      /*!< ADC句柄 */
static volatile ADC_State_e sg_adc_state = ADC_STATE_IDLE;  /*!< ADC当前状态 */
static volatile uint8_t sg_adc_initialized = 0;             /*!< 初始化标志 */

/* Private function prototypes -----------------------------------------------*/
static ADC_Error_e adc_gpio_init(void);
static ADC_Error_e adc_peripheral_init(void);

/* Private functions ---------------------------------------------------------*/

/**
 * @brief       ADC GPIO初始化
 *
 * @param       无
 *
 * @retval      ADC_OK 成功
 * @retval      ADC_ERROR_PARAM 参数错误
 *
 * @note        配置ADC通道对应的GPIO为模拟输入
 */
static ADC_Error_e adc_gpio_init(void)
{
    GPIO_InitTypeDef gpio_init_struct = {0};
    
    /* 使能GPIO时钟 */
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();
    __HAL_RCC_GPIOC_CLK_ENABLE();
    
    /* 配置ADC引脚为模拟输入 */
    gpio_init_struct.Mode = GPIO_MODE_ANALOG;
    gpio_init_struct.Pull = GPIO_NOPULL;
    
    /* 配置PA0-PA7 */
    gpio_init_struct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | 
                           GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
    HAL_GPIO_Init(GPIOA, &gpio_init_struct);
    
    /* 配置PB0-PB1 */
    gpio_init_struct.Pin = GPIO_PIN_0 | GPIO_PIN_1;
    HAL_GPIO_Init(GPIOB, &gpio_init_struct);
    
    /* 配置PC0-PC5 */
    gpio_init_struct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | 
                           GPIO_PIN_4 | GPIO_PIN_5;
    HAL_GPIO_Init(GPIOC, &gpio_init_struct);
    
    return ADC_OK;
}

/**
 * @brief       ADC外设初始化
 *
 * @param       无
 *
 * @retval      ADC_OK 成功
 * @retval      ADC_ERROR_HAL HAL库错误
 *
 * @note        配置ADC工作模式和参数
 */
static ADC_Error_e adc_peripheral_init(void)
{
    ADC_ChannelConfTypeDef sConfig = {0};
    
    /* 使能ADC时钟 */
    __HAL_RCC_ADC1_CLK_ENABLE();
    
    /* 配置ADC参数 */
    sg_adc_handle.Instance = ADC1;
    sg_adc_handle.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV6;
    sg_adc_handle.Init.Resolution = ADC_RESOLUTION_12B;
    sg_adc_handle.Init.ScanConvMode = ADC_SCAN_DISABLE;
    sg_adc_handle.Init.ContinuousConvMode = DISABLE;
    sg_adc_handle.Init.DiscontinuousConvMode = DISABLE;
    sg_adc_handle.Init.ExternalTrigConv = ADC_SOFTWARE_START;
    sg_adc_handle.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    sg_adc_handle.Init.NbrOfConversion = 1;
    sg_adc_handle.Init.DMAContinuousRequests = DISABLE;
    sg_adc_handle.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
    sg_adc_handle.Init.LowPowerAutoWait = DISABLE;
    sg_adc_handle.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
    
    if (HAL_ADC_Init(&sg_adc_handle) != HAL_OK)
    {
        log_e("ADC外设初始化失败");
        return ADC_ERROR_HAL;
    }
    
    /* 配置ADC通道 */
    sConfig.Channel = ADC_CHANNEL_0;
    sConfig.Rank = ADC_REGULAR_RANK_1;
    sConfig.SamplingTime = ADC_SAMPLETIME_387CYCLES_5;
    sConfig.SingleDiff = ADC_SINGLE_ENDED;
    sConfig.OffsetNumber = ADC_OFFSET_NONE;
    sConfig.Offset = 0;
    
    if (HAL_ADC_ConfigChannel(&sg_adc_handle, &sConfig) != HAL_OK)
    {
        log_e("ADC通道配置失败");
        return ADC_ERROR_HAL;
    }
    
    return ADC_OK;
}

/* Exported functions --------------------------------------------------------*/

/**
 * @brief       ADC初始化
 *
 * @param       无
 *
 * @retval      ADC_OK 成功
 * @retval      ADC_ERROR_HAL HAL库错误
 *
 * @note        初始化GPIO、ADC外设
 */
ADC_Error_e adc_init(void)
{
    ADC_Error_e ret;
    
    if (sg_adc_initialized)
    {
        log_w("ADC已初始化");
        return ADC_OK;
    }
    
    /* 初始化GPIO */
    ret = adc_gpio_init();
    if (ret != ADC_OK)
    {
        return ret;
    }
    
    /* 初始化ADC外设 */
    ret = adc_peripheral_init();
    if (ret != ADC_OK)
    {
        return ret;
    }
    
    /* 设置状态 */
    sg_adc_state = ADC_STATE_IDLE;
    sg_adc_initialized = 1;
    
    log_i("ADC初始化完成");
    return ADC_OK;
}

/**
 * @brief       ADC反初始化
 *
 * @param       无
 *
 * @retval      ADC_OK 成功
 * @retval      ADC_ERROR_NOT_INITIALIZED 未初始化
 *
 * @note        关闭ADC外设和释放GPIO资源
 */
ADC_Error_e adc_deinit(void)
{
    if (!sg_adc_initialized)
    {
        log_w("ADC未初始化");
        return ADC_ERROR_NOT_INITIALIZED;
    }
    
    /* 反初始化ADC */
    HAL_ADC_DeInit(&sg_adc_handle);
    
    /* 清除标志 */
    sg_adc_initialized = 0;
    sg_adc_state = ADC_STATE_IDLE;
    
    log_i("ADC已反初始化");
    return ADC_OK;
}

/**
 * @brief       读取ADC通道值
 *
 * @param[in]   channel ADC通道号
 * @param[out]  value 读取的ADC值指针
 *
 * @retval      ADC_OK 成功
 * @retval      ADC_ERROR_NOT_INITIALIZED 未初始化
 * @retval      ADC_ERROR_PARAM 参数错误
 * @retval      ADC_ERROR_TIMEOUT 超时
 *
 * @note        阻塞读操作
 */
ADC_Error_e adc_read_channel(uint32_t channel, uint16_t *value)
{
    if (!sg_adc_initialized)
    {
        log_e("ADC未初始化");
        return ADC_ERROR_NOT_INITIALIZED;
    }
    
    if (value == NULL)
    {
        log_w("ADC读参数错误: value=%p", value);
        return ADC_ERROR_PARAM;
    }
    
    sg_adc_state = ADC_STATE_CONVERTING;
    
    /* 配置通道 */
    ADC_ChannelConfTypeDef sConfig = {0};
    sConfig.Channel = channel;
    sConfig.Rank = ADC_REGULAR_RANK_1;
    sConfig.SamplingTime = ADC_SAMPLETIME_387CYCLES_5;
    sConfig.SingleDiff = ADC_SINGLE_ENDED;
    sConfig.OffsetNumber = ADC_OFFSET_NONE;
    sConfig.Offset = 0;
    
    if (HAL_ADC_ConfigChannel(&sg_adc_handle, &sConfig) != HAL_OK)
    {
        log_e("ADC通道配置失败");
        sg_adc_state = ADC_STATE_ERROR;
        return ADC_ERROR_HAL;
    }
    
    /* 启动转换 */
    if (HAL_ADC_Start(&sg_adc_handle) != HAL_OK)
    {
        log_e("ADC启动失败");
        sg_adc_state = ADC_STATE_ERROR;
        return ADC_ERROR_HAL;
    }
    
    /* 等待转换完成 */
    if (HAL_ADC_PollForConversion(&sg_adc_handle, ADC_READ_TIMEOUT) != HAL_OK)
    {
        log_e("ADC转换超时");
        sg_adc_state = ADC_STATE_ERROR;
        return ADC_ERROR_TIMEOUT;
    }
    
    /* 读取转换结果 */
    *value = HAL_ADC_GetValue(&sg_adc_handle);
    
    /* 停止转换 */
    HAL_ADC_Stop(&sg_adc_handle);
    
    sg_adc_state = ADC_STATE_IDLE;
    log_d("ADC读成功: channel=%lu, value=%d", channel, *value);
    return ADC_OK;
}

/**
 * @brief       读取ADC通道电压
 *
 * @param[in]   channel ADC通道号
 * @param[out]  voltage 读取的电压指针(单位:V)
 *
 * @retval      ADC_OK 成功
 * @retval      ADC_ERROR_NOT_INITIALIZED 未初始化
 * @retval      ADC_ERROR_PARAM 参数错误
 * @retval      ADC_ERROR_TIMEOUT 超时
 *
 * @note        阻塞读操作，电压范围0~3.3V
 */
ADC_Error_e adc_read_voltage(uint32_t channel, float *voltage)
{
    uint16_t adc_value;
    ADC_Error_e ret;
    
    if (voltage == NULL)
    {
        log_w("ADC电压读参数错误: voltage=%p", voltage);
        return ADC_ERROR_PARAM;
    }
    
    /* 读取ADC值 */
    ret = adc_read_channel(channel, &adc_value);
    if (ret != ADC_OK)
    {
        return ret;
    }
    
    /* 转换为电压 (3.3V / 4096) */
    *voltage = (float)adc_value * 3.3f / 4096.0f;
    
    log_d("ADC电压读成功: channel=%lu, voltage=%.3fV", channel, *voltage);
    return ADC_OK;
}

/**
 * @brief       多次采样平均
 *
 * @param[in]   channel ADC通道号
 * @param[in]   times 采样次数
 * @param[out]  value 平均值指针
 *
 * @retval      ADC_OK 成功
 * @retval      ADC_ERROR_NOT_INITIALIZED 未初始化
 * @retval      ADC_ERROR_PARAM 参数错误
 * @retval      ADC_ERROR_TIMEOUT 超时
 *
 * @note        阻塞读操作
 */
ADC_Error_e adc_read_average(uint32_t channel, uint8_t times, uint16_t *value)
{
    uint16_t adc_value;
    uint32_t sum = 0;
    ADC_Error_e ret;
    
    if (value == NULL || times == 0)
    {
        log_w("ADC平均读参数错误: value=%p, times=%d", value, times);
        return ADC_ERROR_PARAM;
    }
    
    /* 多次采样 */
    for (uint8_t i = 0; i < times; i++)
    {
        ret = adc_read_channel(channel, &adc_value);
        if (ret != ADC_OK)
        {
            return ret;
        }
        sum += adc_value;
    }
    
    /* 计算平均值 */
    *value = (uint16_t)(sum / times);
    
    log_d("ADC平均读成功: channel=%lu, times=%d, value=%d", channel, times, *value);
    return ADC_OK;
}

/**
 * @brief       多次采样平均电压
 *
 * @param[in]   channel ADC通道号
 * @param[in]   times 采样次数
 * @param[out]  voltage 平均电压指针(单位:V)
 *
 * @retval      ADC_OK 成功
 * @retval      ADC_ERROR_NOT_INITIALIZED 未初始化
 * @retval      ADC_ERROR_PARAM 参数错误
 * @retval      ADC_ERROR_TIMEOUT 超时
 *
 * @note        阻塞读操作
 */
ADC_Error_e adc_read_voltage_average(uint32_t channel, uint8_t times, float *voltage)
{
    uint16_t adc_value;
    ADC_Error_e ret;
    
    if (voltage == NULL)
    {
        log_w("ADC平均电压读参数错误: voltage=%p", voltage);
        return ADC_ERROR_PARAM;
    }
    
    /* 读取平均ADC值 */
    ret = adc_read_average(channel, times, &adc_value);
    if (ret != ADC_OK)
    {
        return ret;
    }
    
    /* 转换为电压 */
    *voltage = (float)adc_value * 3.3f / 4096.0f;
    
    log_d("ADC平均电压读成功: channel=%lu, times=%d, voltage=%.3fV", channel, times, *voltage);
    return ADC_OK;
}

/**
 * @brief       获取ADC当前状态
 *
 * @param       无
 *
 * @retval      ADC_State_e 当前状态
 *
 * @note        用于状态监控和调试
 */
ADC_State_e adc_get_state(void)
{
    return sg_adc_state;
}

/**
 * @brief       检查ADC是否忙
 *
 * @param       无
 *
 * @retval      1 忙
 * @retval      0 空闲
 *
 * @note        快速检查ADC是否正在转换
 */
uint8_t adc_is_busy(void)
{
    return (sg_adc_state != ADC_STATE_IDLE) ? 1 : 0;
}

/**
 * @brief       打印ADC当前状态（用于调试）
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        显示初始化状态、当前状态等信息
 */
void adc_print_status(void)
{
    const char *state_str[] = {"IDLE", "BUSY", "CONVERTING", "DMA", "ERROR"};
    
    log_i("ADC当前状态:");
    log_i("  初始化状态: %s", sg_adc_initialized ? "已初始化" : "未初始化");
    log_i("  当前状态: %s", state_str[sg_adc_state]);
    log_i("  ADC是否忙: %s", adc_is_busy() ? "是" : "否");
}
